#if VS_TESSELLATION

struct HS_CONTROL_POINT_OUTPUT_SHADOWGEN
{
	hsControlPointShared controlPoint;

#if !_RT_HW_PCF_COMPARE || _RT_CUBEMAP0
	float Depth  : TEXCOORDN;
#endif
};

///////////////// hull shader //////////////////

HS_CONSTANT_DATA_OUTPUT ShadowGenConstantsHS(InputPatch<v2f_sh, 3> p, uint PatchID : SV_PrimitiveID)
{
#if _RT_CUBEMAP0 && !%TEMP_SKIN
	const bool bFrontCull = true;
#else
	// Sun is not using front face culling
	const bool bFrontCull = false;
#endif
	HS_CONSTANT_DATA_OUTPUT output = CommonConstantsHS(p[0].vView.xyz, p[1].vView.xyz, p[2].vView.xyz,
		g_VS_WorldViewPos.xyz, g_VS_ShadowLightPos.xyz, PatchID, bFrontCull);

	return output;
}

[domain("tri")]
[partitioning("fractional_odd")]
[outputtopology("triangle_cw")]
[outputcontrolpoints(3)]
[patchconstantfunc("ShadowGenConstantsHS")]
[maxtessfactor(MAX_TESS_FACTOR)]
HS_CONTROL_POINT_OUTPUT_SHADOWGEN Common_ShadowGenHS(InputPatch<v2f_sh, 3> inputPatch, uint uCPID : SV_OutputControlPointID)
{
	HS_CONTROL_POINT_OUTPUT_SHADOWGEN	output = (HS_CONTROL_POINT_OUTPUT_SHADOWGEN)0;

	output.controlPoint.vView      = inputPatch[uCPID].vView;
	output.controlPoint.vNormal    = inputPatch[uCPID].vNormal.xyz;
	output.controlPoint.vBaseTC.xy = inputPatch[uCPID].baseTC;
#if !_RT_HW_PCF_COMPARE || _RT_CUBEMAP0
	output.Depth                   = inputPatch[uCPID].Depth ;
#endif

	return output;
}

///////////////// domain shader //////////////////

void FillEvalInput_SG(in HS_CONTROL_POINT_OUTPUT_SHADOWGEN triPatch[3], in HS_CONSTANT_DATA_OUTPUT hsConstData, in float3 vBaryCoords, inout CommonEvaluationInputDS evalInput)
{
	evalInput.vBaryCoords = vBaryCoords;
	FillEvalInputControlPoint(triPatch[0].controlPoint, triPatch[1].controlPoint, triPatch[2].controlPoint, hsConstData, evalInput);
	evalInput.vViewPos = g_VS_WorldViewPos.xyz;
}

void ProcessEvalOutput_SG(in CommonEvaluationOutputDS evalOutput, inout v2f_sh dsOutput)
{
	dsOutput.baseTC = evalOutput.vBaseTC.xy;

	const float4 vWorldPos = float4(evalOutput.vPos.xyz, 1);
	dsOutput.HPosition = mul(g_VS_ViewProjMatr, vWorldPos);
}

[domain("tri")]
v2f_sh Common_ShadowGenDS( HS_CONSTANT_DATA_OUTPUT hsConstData, float3 vBaryCoords : SV_DomainLocation, const OutputPatch<HS_CONTROL_POINT_OUTPUT_SHADOWGEN, 3> TrianglePatch )
{
	v2f_sh output = (v2f_sh)0;

	CommonEvaluationInputDS evalInput = (CommonEvaluationInputDS)0;
	FillEvalInput_SG(TrianglePatch, hsConstData, vBaryCoords, evalInput);

	CommonEvaluationOutputDS evalOutput;
	Evaluate(evalInput, evalOutput);
	ProcessEvalOutput_SG(evalOutput, output);

#if !_RT_HW_PCF_COMPARE || _RT_CUBEMAP0
	output.Depth = EvalVec(TrianglePatch[0].Depth, TrianglePatch[1].Depth, TrianglePatch[2].Depth, vBaryCoords);
#endif

	return output;
}

#endif